﻿
using System.Windows.Input;

namespace MvvmFx.Common.ViewModels.Commands
{
    /// <summary>
    /// The abstract base CommandHandler class that implements the <see cref="ICommandHandler"/> 
    /// interface and is responsible for executing a unit of logic when the specified view model command
    /// <see cref="IViewModelCommand"/> executes.
    /// </summary>
    /// <remarks>
    /// A <see cref="CommandHandler"/> is like an <see cref="ICommand"/> in the sense that it
    /// encapsulates a unit of application logic that can be executed via an Execute method.
    /// It is used to specify a unit of code that should be executed when a certain <see cref="ICommand"/> 
    /// executes. 
    /// It can be registered to handle either a specific instance of a command, a Per-Instance Handler,
    /// or the execution of any instance of a specific type of command, a Per-Type Handler.
    /// Derive from this class to implement custom CommandHandlers.
    /// </remarks>
    /// <typeparam name="T">The <see cref="IViewModelCommand"/> command interface.</typeparam>
    public abstract class CommandHandler<T> : ICommandHandler
        where T : IViewModelCommand
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="CommandHandler&lt;T&gt;"/> class.
        /// </summary>
        protected CommandHandler()
        {
            
        }

        /// <summary>
        /// Override and implement the unit of logic to be executed. 
        /// </summary>
        /// <param name="cmd">The command associated to the handler.</param>
        /// <param name="parameter">The parameter to pass to the unit of logic.</param>
        protected abstract void OnExecute(T cmd, object parameter);

        /// <summary>
        /// Executes the specified unit of logic when the command has executed.
        /// </summary>
        /// <param name="cmd">The command associated to the handler.</param>
        /// <param name="parameter">The parameter to pass to the unit of logic.</param>
        public void Execute(T cmd, object parameter)
        {
            OnExecute(cmd, parameter);
        }

        /// <summary>
        /// Executes the specified unit of logic when the command has executed.
        /// </summary>
        /// <param name="cmd">The command <see cref="IViewModelCommand"/> associated to the handler.</param>
        /// <param name="parameter">The parameter to pass to the unit of logic.</param>
        void ICommandHandler.Execute(ICommand cmd, object parameter)
        {
            OnExecute((T)cmd, parameter);
        }
    }

    /// <summary>
    /// The abstract base CommandHandler class that implements the <see cref="ICommandHandler"/> 
    /// interface and is responsible for executing a unit of logic when the specified view model command
    /// <see cref="IViewModelCommand"/> executes.
    /// </summary>
    /// <remarks>
    /// A <see cref="CommandHandler"/> is like an <see cref="ICommand"/> in the sense that it
    /// encapsulates a unit of application logic that can be executed via an Execute method.
    /// It is used to specify a unit of code that should be executed when a certain <see cref="ICommand"/> 
    /// executes. 
    /// It can be registered to handle either a specific instance of a command, a Per-Instance Handler,
    /// or the execution of any instance of a specific type of command, a Per-Type Handler.
    /// Derive from this class to implement custom CommandHandlers.
    /// </remarks>
    public abstract class CommandHandler : ICommandHandler
    {
        /// <summary>
        /// Override and implement the unit of logic to be executed. 
        /// </summary>
        /// <param name="cmd">The command associated to the handler.</param>
        /// <param name="parameter">The parameter to pass to the unit of logic.</param>
        protected abstract void OnExecute(ICommand cmd, object parameter);

        /// <summary>
        /// Execute the specified usint of logic.
        /// </summary>
        /// <param name="cmd">The command associated to the handler.</param>
        /// <param name="parameter">The parameter to pass to the unit of logic.</param>
        public void Execute(ICommand cmd, object parameter)
        {
            OnExecute(cmd, parameter);
        }
    }
}